SPORE.$Import('core.class.base');

/*
---

name: Class.Extras

description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.

license: MIT-style license.

requires: Class

provides: [Class.Extras, Chain, Events, Options]

...
*/

SPORE.register('core.class.extra',function($ns){

	this.Chain = new Class({
	
		$chain: [],
	
		chain: function(){
			this.$chain.append(Array.flatten(arguments));
			return this;
		},
	
		callChain: function(){
			return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
		},
	
		clearChain: function(){
			this.$chain.empty();
			return this;
		}
	
	});
	
	var removeOn = function(string){
		return string.replace(/^on([A-Z])/, function(full, first){
			return first.toLowerCase();
		});
	};
	
	this.Events = new Class({
	
		$events: {},
	
		addEvent: function(type, fn, internal){
			type = removeOn(type);
	
			
	
			this.$events[type] = (this.$events[type] || []).include(fn);
			if (internal) fn.internal = true;
			return this;
		},
	
		addEvents: function(events){
			for (var type in events) this.addEvent(type, events[type]);
			return this;
		},
	
		fireEvent: function(type, args, delay){
			type = removeOn(type);
			var events = this.$events[type];
			if (!events) return this;
			args = Array.from(args);
			events.each(function(fn){
				if (delay) fn.delay(delay, this, args);
				else fn.apply(this, args);
			}, this);
			return this;
		},
		
		removeEvent: function(type, fn){
			type = removeOn(type);
			var events = this.$events[type];
			if (events && !fn.internal){
				var index =  events.indexOf(fn);
				if (index != -1) delete events[index];
			}
			return this;
		},
	
		removeEvents: function(events){
			var type;
			if (typeOf(events) == 'object'){
				for (type in events) this.removeEvent(type, events[type]);
				return this;
			}
			if (events) events = removeOn(events);
			for (type in this.$events){
				if (events && events != type) continue;
				var fns = this.$events[type];
				for (var i = fns.length; i--;) if (i in fns){
					this.removeEvent(type, fns[i]);
				}
			}
			return this;
		}
	
	});
	
	this.Options = new Class({
	
		setOptions: function(){
			var options = this.options = Object.merge.apply(null, [{}, this.options].append(arguments));
			if (this.addEvent) for (var option in options){
				if (typeOf(options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
				this.addEvent(option, options[option]);
				delete options[option];
			}
			return this;
		}
	
	});

});